package com.canyou.activiti.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.canyou.activiti.entity.*;
import com.canyou.activiti.mapper.FormDataItemMapper;
import com.canyou.activiti.mapper.FormDataMapper;
import com.canyou.activiti.mapper.FormDataValMapper;
import com.canyou.activiti.model.FormData;
import com.canyou.activiti.model.FormDataItem;
import com.canyou.activiti.model.FormDataVal;
import com.canyou.activiti.service.ActTaskService;
import com.canyou.enums.ErrorCodeEnum;
import com.canyou.exception.CysBusinessException;
import com.canyou.utils.Oauth2Utils;
import com.canyou.utils.StringUtils;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.runtime.api.model.impl.APITaskConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author canyou
 * @since 2021-03-02
 */
@Service
public class ActTaskServiceImpl implements ActTaskService {

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private FormDataMapper formDataMapper;

    @Autowired
    private FormDataItemMapper formDataItemMapper;

    @Autowired
    private FormDataValMapper formDataValMapper;

    @Override
    public IPage<ActTaskVO> getPageList(IPage<ActTaskVO> page, String taskName, String processDefinitionKey) {
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskCandidateOrAssigned(Oauth2Utils.getUserName())
                .orderByTaskCreateTime().asc()
                .orderByTaskDueDate().asc();
        if (StringUtils.isNotBlank(taskName)) {
            taskQuery.taskNameLikeIgnoreCase("%" + taskName + "%");
        }
        if (StringUtils.isNotBlank(processDefinitionKey)) {
            taskQuery.processDefinitionKeyLikeIgnoreCase("%" + processDefinitionKey + "%");
        }
        // 查询records
        List<Task> taskList = taskQuery.listPage((int) ((page.getCurrent() - 1) * page.getSize()), (int) page.getSize());
        List<ActTaskVO> list = new ArrayList<>();
        if (taskList != null && !taskList.isEmpty()) {
            list = taskList.parallelStream()
                    .map(tk -> {
                        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                                .processInstanceId(tk.getProcessInstanceId())
                                .singleResult();
                        return new ActTaskVO()
                                .setId(tk.getId())
                                .setName(tk.getName())
                                .setBusinessKey(tk.getBusinessKey())
                                .setCreateTime(tk.getCreateTime())
                                .setDescription(tk.getDescription())
                                .setSuspensionState(((TaskEntityImpl) tk).getSuspensionState())
                                .setAssignee(tk.getAssignee())
                                .setStatus(new APITaskConverter().from(tk).getStatus().toString())
                                .setProcessDefinitionKey(processInstance.getProcessDefinitionKey())
                                .setProcessInstanceName(processInstance.getName())
                                .setProcessInstanceId(processInstance.getId());
                    })
                    .collect(Collectors.toList());
        }
        page.setRecords(list);
        // 查询总条数
        page.setTotal(taskQuery.count());
        return page;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void completeTask(String taskId, List<FormDataItemSaveDTO> itemSaveList) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "任务不存在");
        }
        // 如果任务assignee不存在, 则需要先拾取任务
        if (StringUtils.isBlank(task.getAssignee())) {
            taskService.claim(taskId, Oauth2Utils.getUserName());
        }
        HashMap<String, Object> variables = new HashMap<>(10);
        if (itemSaveList != null && !itemSaveList.isEmpty()) {
            itemSaveList.stream()
                    .filter(FormDataItemSaveDTO::getIsParam)
                    .forEach(item -> variables.put(item.getControlId(), item.getUserVal()));
        }
        if (!variables.isEmpty()) {
            taskService.setVariables(taskId, variables);
        }
        taskService.complete(taskId);
    }

    @Override
    public FormDataVO getFormData(String taskId) {
        String formKey = null;
        String processDefinitionId = null;
        String assignee = null;
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 如果该任务已经到历史任务中
        if (task == null) {
            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                    .taskId(taskId).singleResult();
            if (historicTaskInstance == null) {
                throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "任务不存在");
            }
            formKey = historicTaskInstance.getFormKey();
            processDefinitionId = historicTaskInstance.getProcessDefinitionId();
            assignee = historicTaskInstance.getAssignee();
        } else {
            formKey = task.getFormKey();
            processDefinitionId = task.getProcessDefinitionId();
            assignee = task.getAssignee();
        }

        // 表单主体
        FormData formData = formDataMapper.selectOne(Wrappers
                .<FormData>lambdaQuery()
                .eq(FormData::getFormKey, formKey)
                .eq(FormData::getProcDefId, processDefinitionId));
        if (formData == null) {
            return null;
        }
        FormDataVO formDataVO = new FormDataVO()
                .setFormId(formData.getFormId())
                .setFormKey(formData.getFormKey())
                .setFormName(formData.getFormName())
                .setProcDefId(formData.getProcDefId())
                .setAssignee(assignee)
                .setTaskId(taskId);
        List<FormDataItem> itemList = formDataItemMapper.selectList(Wrappers
                .<FormDataItem>lambdaQuery()
                .eq(FormDataItem::getFormDataId, formData.getId()));
        if (itemList == null || itemList.isEmpty()) {
            return formDataVO;
        }
        // 构建表单项
        List<FormDataItemVO> itemVOList = new ArrayList<>();
        itemList.stream().forEach(item -> {
            FormDataItemVO itemVO = new FormDataItemVO()
                    .setControlId(item.getControlId())
                    .setControlName(item.getControlName())
                    .setControlType(item.getControlType())
                    .setDataType(item.getDataType())
                    .setDefaultVal(item.getDefaultVal())
                    .setPlaceHolder(item.getPlaceHolder())
                    .setValidateConstraint(item.getValidateConstraint())
                    .setOptionalVal(item.getOptionalVal())
                    .setIsRequired(!Integer.valueOf(0).equals(item.getIsRequired()));
            // 找用户已有输入值
            FormDataVal formDataVal = formDataValMapper.selectOne(Wrappers
                    .<FormDataVal>lambdaQuery()
                    .eq(FormDataVal::getItemId, item.getId())
                    .eq(FormDataVal::getTaskId, taskId));
            if (formDataVal != null) {
                itemVO.setUserVal(formDataVal.getUserVal());
            }
            itemVOList.add(itemVO);
        });
        formDataVO.setFormDataItemList(itemVOList);
        return formDataVO;
    }

    @Override
    public boolean checkFormData(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "任务不存在");
        }
        Long count = formDataMapper.selectCount(Wrappers
                .<FormData>lambdaQuery()
                .eq(FormData::getFormKey, task.getFormKey())
                .eq(FormData::getProcDefId, task.getProcessDefinitionId()));
        return count != null && count.compareTo(0L) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<FormDataItemSaveDTO> saveFormData(FormDataSaveDTO formDataSaveDTO) {
        Task task = taskService.createTaskQuery().taskId(formDataSaveDTO.getTaskId()).singleResult();
        if (task == null) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "任务不存在");
        }
        FormData formData = formDataMapper.selectOne(Wrappers
                .<FormData>lambdaQuery()
                .eq(FormData::getFormKey, task.getFormKey())
                .eq(FormData::getProcDefId, task.getProcessDefinitionId()));
        if (formData == null) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "表单不存在");
        }
        List<FormDataItem> itemList = formDataItemMapper.selectList(Wrappers
                .<FormDataItem>lambdaQuery()
                .eq(FormDataItem::getFormDataId, formData.getId()));
        if (itemList == null || itemList.isEmpty()) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "表单没有数据项");
        }
        List<FormDataItemSaveDTO> items = itemList.stream().map(item -> {
            FormDataVal formDataVal = new FormDataVal();
            formDataVal.setTaskId(task.getId());
            formDataVal.setProcDefId(task.getProcessDefinitionId());
            formDataVal.setProcInstId(task.getProcessInstanceId());
            formDataVal.setItemId(item.getId());
            formDataVal.setControlId(item.getControlId());
            FormDataItemSaveDTO formDataItemSaveDTO = formDataSaveDTO.getItemList()
                    .stream()
                    .filter(i -> item.getControlId().equalsIgnoreCase(i.getControlId()))
                    .findFirst()
                    .orElse(null);
            if (formDataItemSaveDTO != null) {
                formDataVal.setUserVal(formDataItemSaveDTO.getUserVal());
            }
            formDataValMapper.insert(formDataVal);
            return new FormDataItemSaveDTO()
                    .setControlId(item.getControlId())
                    .setUserVal(formDataItemSaveDTO != null ? formDataItemSaveDTO.getUserVal() : null)
                    .setIsParam(item.getIsRequired() != null && Integer.valueOf(1).equals(item.getIsRequired()));
        }).collect(Collectors.toList());
        this.completeTask(formDataSaveDTO.getTaskId(), items);
        return items;
    }

}
